let Vue;

class Store {
  constructor(options) {
    // 1. 实现 state：响应式的 全局Vue data
    this._vm = new Vue({
      data: {
        // 加两个$，Vue不做代理
        $$state: options.state,
      },
    });

    // 2. 实现 getters：依次执行 options.getters 中的每个方法
    options.getters && this.handlerGetters(options.getters);

    // 3. 实现 commit：根据参数type，执行 options.mutations[type](state) 方法
    this._mutations = options.mutations;
    // 3.2 注意绑定 this
    this.commit = this.commit.bind(this);

    // 4. 实现 dispatch：根据参数type，执行 options.actions[type](this) 方法
    this._actions = options.actions;
    // 4. 注意绑定 this
    this.dispatch = this.dispatch.bind(this);
  }

  // 1.1 保护 state，不能在直接修改 state
  get state() {
    return this._vm._data.$$state;
  }
  set state(val) {
    console.error(`不能直接修改 state 为${val} ，请通过commit 或 dispatch 方式`);
  }

  handlerGetters(getters) {
    this.getters = {};
    Object.keys(getters).forEach((key) => {
      Object.defineProperty(this.getters, key, {
        // getters 的属性是只读的
        get: () => {
          return getters[key](this.state);
        },
      });
    });
  }

  commit(type, payload) {
    const entry = this._mutations[type];
    if (entry) {
      entry(this.state, payload);
    }
  }

  dispatch(type, payload) {
    const entry = this._actions[type];
    if (entry) {
      entry(this, payload);
    }
  }
}

function install(_Vue) {
  Vue = _Vue;
  // 把 $store 混入到 Vue 组件的根实例上
  Vue.mixin({
    beforeCreate() {
      if (this.$options.store) {
        Vue.prototype.$store = this.$options.store;
      }
    },
  });
}

export default {
  Store,
  install,
};
